package cn.bupt.adt.util;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.bupt.adt.constant.Constants;
import cn.bupt.adt.util.IPUtil;

/**
 * 
 * <p>
 * Title:ImageUtil
 * </p>
 * <p>
 * Description:图片处理类，包括生成缩略图
 * </p>
 * 
 * @author waiting
 * @date 2016年5月30日 上午10:54:41
 */
public class ImageUtil {
	private static final ObjectMapper mapper = new ObjectMapper();  
	//图片上传的路径分为3级，根目录为 域名：1级：端口号/upload/(永远固定)|2级： 文件夹名（身份证、学历）/时间名/  | 3级： 文件名(xxx.jpg)
	public static String uploadImage(MultipartFile file, String dir,String rootPath,int count){
		String orginalName =file.getOriginalFilename();
		String[] spl = orginalName.split("\\.");
		String fileName = null;
		try {
			fileName = count+"_"+"src."+spl[spl.length-1];
			File parDir = new File(rootPath+dir);
			if(!parDir.exists())
				parDir.mkdirs();
			file.transferTo(new File(rootPath+dir+fileName));
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return dir+fileName;
	}
	public static String uploadSuoLveImage(MultipartFile productPic, String fileName)
			throws IllegalStateException, IOException {
		// 上传图片
		if (productPic != null) {
			String fileType = productPic.getContentType();// 文件类型 格式如：image/jpeg
			String[] fileTypeArr = fileType.split("/");//

			// 文件类型是图片
			if (fileTypeArr[0].equals("image")) {
				// 存储新图片的物理路径
				String srcPicPathString = fileName;
				// 新建一个文件夹
				ImageUtil.generateFile(srcPicPathString);
				// 原始文件的名字
				productPic.getOriginalFilename();
				// 生成新的图片名称
				String newFileName = Constants.NEW_FILE_NAME + "."
						+ fileTypeArr[1];
				// 新图片地址
				String newFilePathString = srcPicPathString + "/" + newFileName;
				// 创建新图片
				File newFile = new java.io.File(newFilePathString);
				// 将内存中的数据写入磁盘
				productPic.transferTo(newFile);
				// 生成图片缩略图
				int targetFileWidth = 240;
				String targetFile = srcPicPathString + "/" + targetFileWidth+"."
						+ fileTypeArr[1];
				ImageUtil.AffineTransImage(newFilePathString, targetFile,
						targetFileWidth);
				return targetFileWidth+"." + fileTypeArr[1];//返回src.jpg这种格式
			} else {
				System.out.println(fileTypeArr[0]);
				return null;
			}
			
		} else {
			return null;
		}
	}

	/**
	 * 生成文件夹
	 * 
	 * @param fileName
	 * @return
	 */
	public static void generateFile(String fileName) {
		System.out.println(fileName);
		File file = new File(fileName);
		file.mkdirs();
	}

	/**
	 * 生成图片缩略图
	 * 
	 * @param srcFile
	 *            源文件的地址
	 * @param targetFile
	 *            目标文件的地址
	 * @param targetFileWidth
	 *            目标图片的宽度
	 */
	public static double AffineTransImage(String srcFile, String targetFile,
			int targetFileWidth) {
	    double Getratio = 0;
		try {
			File fi = new File(srcFile); // 大图文件
			File fo = new File(targetFile);// 将要转换出的小图文件
			int nw = targetFileWidth; // 新生成的图片的宽度
			/*
			 * AffineTransform 类表示 2D 仿射变换，它执行从 2D 坐标到其他 2D
			 * 坐标的线性映射，保留了线的“直线性”和“平行性”。可以使用一系 列平移、缩放、翻转、旋转和剪切来构造仿射变换。
			 */
			AffineTransform transform = new AffineTransform();
			BufferedImage bis = ImageIO.read(fi); // 读取图片
			int w = bis.getWidth(); // 原图的宽度
			int h = bis.getHeight(); // 原图的高度
			// double scale = (double)w/h;
			int nh = (nw * h) / w;
			double sx = (double) nw / w;
			double sy = (double) nh / h;
			Getratio= sx/sy;
//			System.out.println("Getratio1="+Getratio);
			transform.setToScale(sx, sy); // setToScale(double sx, double sy)
											// 将此变换设置为缩放变换。
			/*
			 * AffineTransformOp类使用仿射转换来执行从源图像或 Raster 中 2D 坐标到目标图像或 Raster 中 2D
			 * 坐标的线性映射。所使用的插值类型由构造方法通过 一个 RenderingHints 对象或通过此类中定义的整数插值类型之一来指定。
			 * 如果在构造方法中指定了 RenderingHints 对象，则使用插值提示和呈现
			 * 的质量提示为此操作设置插值类型。要求进行颜色转换时，可以使用颜色 呈现提示和抖动提示。 注意，务必要满足以下约束：源图像与目标图像
			 * 必须不同。 对于 Raster 对象，源图像中的 band 数必须等于目标图像中 的 band 数。
			 */
			AffineTransformOp ato = new AffineTransformOp(transform, null);
			BufferedImage bid = new BufferedImage(nw, nh,
					BufferedImage.TYPE_3BYTE_BGR);
			/*
			 * TYPE_3BYTE_BGR 表示一个具有 8 位 RGB 颜色分量的图像， 对应于 Windows 风格的 BGR
			 * 颜色模型，具有用 3 字节存 储的 Blue、Green 和 Red 三种颜色。
			 */
			ato.filter(bis, bid);
//			System.out.println("Getratio2="+Getratio);
			ImageIO.write(bid, "jpeg", fo);
		} catch (Exception e) {
			e.printStackTrace();
		}
//		System.out.println("Getratio3="+Getratio);
        return  Getratio;
	}
	public static List<String> convertToList(String picture){
		List<String> beanList = new ArrayList<String>();
//		ObjectMapper mapper = new ObjectMapper();  
	    try {
	    	beanList = mapper.readValue(picture, new TypeReference<List<String>>() {});
		} catch (Exception e) {
			e.printStackTrace();
			return new ArrayList<>();
		}
	    return beanList;
	}
	/**
	 * 根据数据库中存储的相对路径，构造完整的图片路径
	 * @param rawPath 一张图片的相对路径 应是 xxx/xxxx/**的形式
	 * @return
	 */
	public static String contructFullImagePath(String rawPath,HttpServletRequest request) {
		return "http://" + IPUtil.getIpAddr(request) +":"+request.getLocalPort()+"/"+Constants.IMAGE_PATH+rawPath;
	}

}
